<template>
  <div class="threeJS"></div>
</template>

<script>
import * as THREE from "three";
import { PDBLoader } from "three/examples/jsm/loaders/PDBLoader";
import { TrackballControls } from "three/examples/jsm/controls/TrackballControls";
import { CSS2DRenderer, CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer";

export default {
  name: "dos",
  components: {},
  data() {
    return {}
  },

  methods: {
    init() {
      this.scene = new THREE.Scene();
      this.div = document.querySelector(".threeJS");
      this.width = this.div.clientWidth;
      this.height = this.div.clientHeight;
      this.group = new THREE.Group();
      this.scene.add(this.group);

      this.initLight();
      this.initCamera();
      this.initRenderer();
      this.ininCSS2DRender();
      this.render();
    },


    ininCSS2DRender() {
      let labelRenderer = new CSS2DRenderer();
      this.labelRenderer = labelRenderer;
      labelRenderer.setSize(this.width, this.height);
      labelRenderer.domElement.style.position = 'absolute';
      labelRenderer.domElement.style.top = '50px';
      labelRenderer.domElement.style.pointerEvents = 'none';  // 元素不再是鼠标事件的目标

      this.div.appendChild(labelRenderer.domElement);

      // 鼠标键盘 控件
      let controls = new TrackballControls(this.camera, this.renderer.domElement);
      this.controls = controls;
      controls.minDistance = 500;
      controls.maxDistance = 2000;

      this.loadMolecule();
    },


    loadMolecule() {
      let _this = this;
      let filePath = "/static/models/pdb";
      let pdbLoader = new PDBLoader();

      pdbLoader.load(filePath + '/caffeine.pdb', function (pdb) {
        console.log(pdb);

        var geometryAtoms = pdb.geometryAtoms;  // 几何原子
        var geometryBonds = pdb.geometryBonds;  // 结合几何
        let offset = new THREE.Vector3();

        var boxGeometry = new THREE.BoxBufferGeometry(1, 1, 1);  // 立方缓冲几何体
        var sphereGeometry = new THREE.IcosahedronBufferGeometry(1, 3);  // 二十面缓冲几何体

        geometryAtoms.computeBoundingBox();  // 计算边界框

        geometryAtoms.boundingBox.getCenter(offset);
        // geometryAtoms.boundingBox.getCenter( offset ).negate();  // negate 取反

        geometryAtoms.translate(offset.x, offset.y, offset.z);
        geometryBonds.translate(offset.x, offset.y, offset.z);

        var positions = geometryAtoms.getAttribute('position');  // 获取 position 属性
        var colors = geometryAtoms.getAttribute('color');

        var position = new THREE.Vector3();
        var color = new THREE.Color();

        for (var i = 0; i < positions.count; i++) {

          position.x = positions.getX(i);
          position.y = positions.getY(i);
          position.z = positions.getZ(i);

          color.r = colors.getX(i);
          color.g = colors.getY(i);
          color.b = colors.getZ(i);

          var material = new THREE.MeshPhongMaterial({color: color});  // 给物体设置颜色材质
          var object = new THREE.Mesh(sphereGeometry, material);

          object.position.copy(position);
          object.position.multiplyScalar(75);  // 缩放模型大小
          object.scale.multiplyScalar(25);
          _this.group.add(object);

          _this.addDomItem(i, object);
        }

        _this.setTextPosition(geometryBonds, boxGeometry);
      });
    },


    // 添加文字
    addDomItem(index, object) {
      var text = document.createElement('div');
      text.className = 'label';

      text.style.color = "#333333";
      text.style.border = "1px solid #d8d8d8";
      text.style.padding = "4px 0px";
      text.style.borderRadius = "2px";
      text.style.background = "rgba(255,255,255,0.9)";
      text.style.boxShadow = "0px 4px 12px rgba(0, 0, 0, 0.1)";
      text.style.lineHeight = "15px";
      text.style.fontSize = "12px";

      text.innerHTML = `
                    <div style="transform: scale(0.86);"><span>测点名称：</span><span>监测点${index}</span></div>
                    <div style="transform: scale(0.86);"><span>测点数据：</span><span>23432</span></div>`;

      var label = new CSS2DObject(text);
      label.position.copy(object.position);
      this.group.add(label);
    },


    // 设置文字位置
    setTextPosition(geometryBonds, boxGeometry) {
      let positions = geometryBonds.getAttribute('position');

      var start = new THREE.Vector3();
      var end = new THREE.Vector3();

      for (var i = 0; i < positions.count; i += 2) {

        start.x = positions.getX(i);
        start.y = positions.getY(i);
        start.z = positions.getZ(i);

        end.x = positions.getX(i + 1);
        end.y = positions.getY(i + 1);
        end.z = positions.getZ(i + 1);

        start.multiplyScalar(75);
        end.multiplyScalar(75);

        var object = new THREE.Mesh(boxGeometry, new THREE.MeshPhongMaterial(0xffffff));
        object.position.copy(start);
        object.position.lerp(end, 0.5);
        object.scale.set(5, 5, start.distanceTo(end));
        object.lookAt(end);

        this.group.add(object);
      }

      this.render();
    },


    // 创建光源
    initLight() {
      // 平行光
      var point = new THREE.DirectionalLight(0xc29e5e);
      point.position.set(0, 400, 100);
      this.scene.add(point);

      // 环境光 颜色设置为`0xffffff`,强度系数设置为0.5
      var ambient = new THREE.AmbientLight(0xd9b26e, 0.06);
      this.scene.add(ambient);
    },

    // 创建相机
    initCamera() {
      var k = this.width / this.height;
      var s = 300; // 三维场景显示范围控制系数，系数越大，显示的范围越大
      var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 10000); // 正投影相机
      this.camera = camera;

      camera.position.set(800, 800, 800);
      camera.lookAt(this.scene.position);
    },


    // 创建渲染器对象
    initRenderer() {
      // antialias  渲染器是否需要高质量渲染（高质量渲染没有锯齿，如果数据量大可以改为 false）
      var renderer = new THREE.WebGLRenderer({antialias: true});
      this.renderer = renderer;

      renderer.setSize(this.width, this.height);   // 设置渲染区域尺寸
      renderer.setClearColor(0xf0f0f0, 1);
      this.div.appendChild(renderer.domElement);
    },


    // 渲染模型
    render() {
      this.renderer.render(this.scene, this.camera);
      this.labelRenderer.render(this.scene, this.camera);

      requestAnimationFrame(this.render);
      this.controls.update();
    },
  }
}
</script>

<style scoped lang="scss">
.threeJS {
  height: 500px;
}
</style>
